---
title: Error handling
---

<Note>

Starting with version 4.0.0, Apollo Kotlin offers a way to handle errors automatically at parsing time. Fields that are nullable only for error purposes can also be generated as non-null in Kotlin. You can read more about it in the ["handling nullability" page](../advanced/nullability).

</Note>

## `ApolloResponse` 

`ApolloResponse` contains three important fields:
* `exception` contains the fetch error if any.
* `errors` contains the GraphQL errors if any.
* `data` contains the returned (potentially partial) data if any.

Use `ApolloResponse.data` to check if the server returned data:

```kotlin
if (response.data != null) {
  // Handle (potentially partial) data
} else {
  // Something wrong happened
  if (response.exception != null) {
    // Handle fetch errors
  } else {
    // Handle GraphQL errors in response.errors
  }
}
```

This is also true when calling `toFlow()` (e.g. with [subscriptions](/kotlin/essentials/subscriptions)) and `watch()` (with the [normalized cache](/kotlin/caching/query-watchers)).

```kotlin
apolloClient.subscription(subscription).toFlow().collect { response ->
  if (response.data != null) {
    // Handle (potentially partial) data
  } else {
    if (response.exception != null) {
      // Handle fetch errors
    } else {
      // Handle GraphQL errors in response.errors
    }
  }
}
```

If you prefer throwing, you can use `dataOrThrow()` to get a non-null data:

```kotlin
val data = apolloClient.query(ExampleQuery()).execute().dataOrThrow()
// data is non-null
```

## Different types of errors

Whenever you execute a GraphQL operation with Apollo Kotlin (or any other GraphQL client), two types of errors can occur:

* **Fetch errors**: a GraphQL response wasn't received because an error occurred while communicating with your GraphQL server. This might be an SSL error, a socket error because your app is offline, or a 500 or any other HTTP error. When a fetch error occurs, no data is returned and `response.exception` is non-null.
* **GraphQL errors**: a GraphQL response _is_ received (HTTP 200), and it contains a non-empty [`errors`](https://spec.graphql.org/draft/#sec-Errors) field. This means the server wasn't able to completely process the query. The response might include _partial_ data if the server was able to process _some_ of the query.

### Fetch errors

Fetch errors happen when it's impossible to fetch a GraphQL response. They can have a wide variety of causes (non-exhaustive list):

* The app is offline or doesn't have access to the network.
* A DNS error occurred, making it impossible to look up the host.
* An SSL error occurred (e.g., the server certificate isn't trusted).
* The connection was closed.
* The server responded with a non-successful HTTP code.
* The server didn't respond with valid JSON.
* The response JSON doesn't satisfy the schema and cannot be parsed.
* A request was specified as CacheOnly but the data wasn't cached.
* And more...

You can display an error based on the exception in `response.exception`  

### GraphQL errors

GraphQL errors happen when a GraphQL response is successfully fetched but contains GraphQL errors. In that case, the response may contain partial data. 

For example, the following query uses an invalid `id` to look up a `Person`:

```graphql
query FilmAndPersonQuery {
  film(id: "ZmlsbXM6MQ==") {
    title
  }
  person(id: "badId") {
    name
  }
}
```

The server will return the following response:

```json
{
  "data": {
    "film": {
      "title": "A New Hope"
    },
    "person": null
  },
  "errors": [
    {
      "message": "Cannot find person with id 'badId'",
      "path": ["person"]
    }
  ]
}
```

`person` is null:

```kotlin
// there was an error fetching data
println(response.data?.person) // null
// read the error from response.errors
println(response.errors?.first()?.message) // "Cannot find person with id 'badId'"
// partial data is also returned
println(response.data?.film?.title) //  "A New Hope"
// exception is null
println(response.exception) // null
```

This allows to display as much data as possible without having to do a new network round trip.

Because GraphQL models both errors and semantic nulls as nullable fields, you must check `errors` to determine whether the field is an error or a true null.

For an example, it is possible for a person to not have a starship:

```json
{
  "data": {
    "person": {
      "starship": null
    }
  }
}
```

In that case, `starship` is a true null and not an error.

## Truth table

| exception | data      | errors    | meaning                                                                     |
|-----------|-----------|-----------|-----------------------------------------------------------------------------|
| `null`    | `null`    | `null`    | Non-compliant server, if `data` is null, there should be at least one error |
| `null`    | `null`    | `present` | A GraphQL request error happened or a Graph field error bubbled up.         |
| `null`    | `present` | `null`    | Complete data was received.                                                 |
| `null`    | `present` | `present` | Partial data was received alongside field error(s).                         |
| `present` | `null`    | `null`    | A fetch error happened.                                                     |
| `present` | `null`    | `present` | 🙅‍♂️ impossible.                                                           |
| `present` | `present` | `null`    | 🙅‍♂️ impossible.                                                           |
| `present` | `present` | `present` | 🙅‍♂️ impossible.                                                           |
